package com.jcl.core.db.config;

import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.jcl.core.constants.Constant;
import com.jcl.core.db.DbServerTools;
import com.jcl.core.db.DynamicDataSource;
import com.jcl.core.db.InitDataSource;
import com.jcl.core.db.constant.DbProperty;
import com.jcl.core.db.model.DataSourceEnum;
import com.jcl.core.db.model.InitDataSourceModel;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;
import java.util.Map;
import java.util.Properties;


/* *
 * @Author yyliu
 * @Description springboot集成mybatis的基本入口
 * 1）创建数据源(如果采用的是默认的tomcat-jdbc数据源，则不需要)
 * 2）创建SqlSessionFactory
 * 3）配置事务管理器，除非需要使用事务，否则不用配置
 * @Date 18:51 2018/12/18
**/
public class DataSourceConfiguration {

    protected String dataSourcePrefix;

    protected String modelPackage;

    protected String mapperLocation;

    private String dbServerSql;

    private String dbCorpSql;

    protected Environment env;

    public DataSourceConfiguration(String dataSourcePrefix,
                                   String modelPackage,
                                   String mapperLocation,
                                   Environment env) {
        this.dataSourcePrefix = dataSourcePrefix;
        this.modelPackage = modelPackage;
        this.mapperLocation = mapperLocation;
        this.env = env;
        DbProperty.setPrefix(dataSourcePrefix);
    }

    public DbServerTools dbServerTools(){
        DbServerTools tools = new DbServerTools();
        if(null != dbServerSql){
            tools.setDbServerSql(dbServerSql);
        }
        if(null != dbCorpSql){
            tools.setDbCorpSql(dbCorpSql);
        }
        return tools;
    }
    /**
     * 创建默认数据源
     */
    public DataSource consoleDataSource() throws Exception {
        Properties props = new Properties();
        props.put(DataSourceEnum.DRIVER_CLASS_NAME.getName(), env.getProperty(DbProperty.getJdbcDriver()));
        props.put(DataSourceEnum.DB_URL.getName(), env.getProperty(DbProperty.getJdbcUrl()));
        props.put(DataSourceEnum.DB_USERNAME.getName(), env.getProperty(DbProperty.getUsername()));
        props.put(DataSourceEnum.DB_PASSWORD.getName(), env.getProperty(DbProperty.getPassword()));

        props.put(DataSourceEnum.DB_initialSize.getName(), env.getProperty(DbProperty.getInitialSize()));
        props.put(DataSourceEnum.DB_maxWait.getName(), env.getProperty(DbProperty.getMaxWait()));
        props.put(DataSourceEnum.DB_maxActive.getName(), env.getProperty(DbProperty.getMaxActive()));
        props.put(DataSourceEnum.DB_minIdle.getName(), env.getProperty(DbProperty.getMinIdle()));
        props.put(DataSourceEnum.DB_testOnBorrow.getName(), env.getProperty(DbProperty.getTestOnBorrow()));
        props.put(DataSourceEnum.DB_testOnReturn.getName(), env.getProperty(DbProperty.getTestOnReturn()));
        props.put(DataSourceEnum.DB_testWhileIdle.getName(), env.getProperty(DbProperty.getTestWhileIdle()));
        props.put(DataSourceEnum.DB_logAbandoned.getName(), env.getProperty(DbProperty.getLogAbandoned()));
        props.put(DataSourceEnum.DB_removeAbandoned.getName(), env.getProperty(DbProperty.getRemoveAbandoned()));
        props.put(DataSourceEnum.DB_validationQuery.getName(), env.getProperty(DbProperty.getValidationQuery()));

        props.put(DataSourceEnum.DB_maxPoolPreparedStatementPerConnectionSize.getName(),
                env.getProperty(DbProperty.getMaxPoolPreparedStatementPerConnectionSize()));
        props.put(DataSourceEnum.DB_minEvictableIdleTimeMillis.getName(),
                env.getProperty(DbProperty.getMinEvictableIdleTimeMillis()));
        props.put(DataSourceEnum.DB_removeAbandonedTimeout.getName(),
                env.getProperty(DbProperty.getRemoveAbandonedTimeout()));
        props.put(DataSourceEnum.DB_timeBetweenEvictionRunsMillis.getName(),
                env.getProperty(DbProperty.getTimeBetweenEvictionRunsMillis()));
        props.put(DataSourceEnum.DB_poolPreparedStatements.getName(),
                env.getProperty(DbProperty.getPoolPreparedStatements()));

        return DruidDataSourceFactory.createDataSource(props);
    }

    /**
     * @Primary 该注解表示在同一个接口有多个实现类可以注入的时候，默认选择哪一个，而不是让@autowire注解报错
     * @Qualifier 根据名称进行注入，通常是在具有相同的多个类型的实例的一个注入（例如有多个DataSource类型的实例）
     */
    public DynamicDataSource dataSource(DataSource consoleDataSource) {

        InitDataSourceModel model = dbServerTools().getInitDataSourceModel(consoleDataSource);
        Map<Object, Object> targetDataSources = InitDataSource.targetDataSources(model,
                env.getProperty(DbProperty.getJdbcDriver()));
        targetDataSources.put(Constant.DEFAULT_DB_NAME, consoleDataSource);
        DynamicDataSource dataSource = new DynamicDataSource();
        //DruidDataSource dataSource = new DruidDataSource();
        dataSource.setTargetDataSources(targetDataSources);// 该方法是AbstractRoutingDataSource的方法
        dataSource.setDefaultTargetDataSource(consoleDataSource);// 默认的datasource设置为consoleDataSource

        return dataSource;
    }

    /**
     * 根据数据源创建SqlSessionFactory
     */
    public SqlSessionFactory sqlSessionFactory(DynamicDataSource ds) throws Exception {
        SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
        factory.setDataSource(ds);// 指定数据源(这个必须有，否则报错)
        // 下边两句仅仅用于*.xml文件，如果整个持久层操作不需要使用到xml文件的话（只用注解就可以搞定），则不加
        factory.setTypeAliasesPackage(modelPackage);// 指定基包
        factory.setConfigLocation(new ClassPathResource(mapperLocation));
        /*fb.setMapperLocations(
                new PathMatchingResourcePatternResolver().
                        getResources(MAPPER_LOCATION));*/

        return factory.getObject();
    }

    /**
     * 配置事务管理器
     */
    public DataSourceTransactionManager transactionManager(DynamicDataSource dataSource) throws Exception {
        return new DataSourceTransactionManager(dataSource);
    }

    public String getDataSourcePrefix() {
        return dataSourcePrefix;
    }

    public void setDataSourcePrefix(String dataSourcePrefix) {
        this.dataSourcePrefix = dataSourcePrefix;
    }

    public String getModelPackage() {
        return modelPackage;
    }

    public void setModelPackage(String modelPackage) {
        this.modelPackage = modelPackage;
    }

    public String getMapperLocation() {
        return mapperLocation;
    }

    public void setMapperLocation(String mapperLocation) {
        this.mapperLocation = mapperLocation;
    }

    public String getDbServerSql() {
        return dbServerSql;
    }

    public void setDbServerSql(String dbServerSql) {
        this.dbServerSql = dbServerSql;
    }

    public String getDbCorpSql() {
        return dbCorpSql;
    }

    public void setDbCorpSql(String dbCorpSql) {
        this.dbCorpSql = dbCorpSql;
    }

    public Environment getEnv() {
        return env;
    }

    public void setEnv(Environment env) {
        this.env = env;
    }
}